---
title: Types
sidebar_position: 1
description: Standard Mojo data types.
---

All values in Mojo have an associated data type. Most of the types are
*nominal* types, defined by a [`struct`](/mojo/manual/structs). These types are
nominal (or "named") because type equality is determined by the type's *name*,
not its *structure*.

There are some types that aren't defined as structs:

* Functions are typed based on their signatures.
* `NoneType` is a type with one instance, the `None` object, which is used to
  signal "no value."

Mojo comes with a standard library that provides a number of useful types and
utility functions. These standard types aren't privileged. Each of the standard
library types is defined just like user-defined types—even basic types like
[`Int`](/mojo/stdlib/builtin/int/Int) and
[`String`](/mojo/stdlib/collections/string/string/String). But these standard library
types are the building blocks you'll use for most Mojo programs.

The most common types are *built-in types*, which are always available and
don't need to be imported. These include types for numeric values, strings,
boolean values, and others.

The standard library also includes many more types that you can import as
needed, including collection types, utilities for interacting with the
filesystem and getting system information, and so on.

## Numeric types

Mojo's most basic numeric type is `Int`, which represents a signed integer of
the largest size supported by the system—typically 64 bits or 32 bits.

Mojo also has built-in types for integer, unsigned integer, and floating-point
values of various precisions:

<figure id="table-1">

| Type name | Description                                           |
| --------- | ----------------------------------------------------- |
| `Int8`    | 8-bit signed integer                                  |
| `UInt8`   | 8-bit unsigned integer                                |
| `Int16`   | 16-bit signed integer                                 |
| `UInt16`  | 16-bit unsigned integer                               |
| `Int32`   | 32-bit signed integer                                 |
| `UInt32`  | 32-bit unsigned integer                               |
| `Int64`   | 64-bit signed integer                                 |
| `UInt64`  | 64-bit unsigned integer                               |
| `Int128`  | 128-bit signed integer                                |
| `UInt128` | 128-bit unsigned integer                              |
| `Int256`  | 256-bit signed integer                                |
| `UInt256` | 256-bit unsigned integer                              |
| `Float16` | 16-bit floating point number (IEEE 754-2008 binary16) |
| `Float32` | 32-bit floating point number (IEEE 754-2008 binary32) |
| `Float64` | 64-bit floating point number (IEEE 754-2008 binary64) |

<figcaption><b>Table 1.</b> Numeric types with specific precision</figcaption>
</figure>

The types in Table 1 are actually all aliases to a single type,
[`SIMD`](/mojo/stdlib/builtin/simd/SIMD), which is discussed later.

All of the numeric types support the usual numeric and bitwise operators. The
[`math`](/mojo/stdlib/math/) module provides a number of additional math
functions.

You may wonder when to use `Int` and when to use the other integer
types. In general, `Int` is a good safe default when you need an integer type
and you don't require a specific bit width. Using `Int` as the default integer
type for APIs makes APIs more consistent and predictable.

### Signed and unsigned integers

Mojo supports both signed (`Int`) and unsigned (`UInt`) integers. You can use
the general `Int` or `UInt` types when you do not require a specific bit width.
Note that any alias to a fixed-precision type will be of type
[`SIMD`](/mojo/stdlib/builtin/simd/SIMD).

You might prefer to use unsigned integers over signed integers in conditions
where you don't need negative numbers, are not writing for a public API, or need
additional range.

Mojo's `UInt` type represents an unsigned integer of the
[word size](https://en.wikipedia.org/wiki/Word_\(computer_architecture\)) of the
CPU, which is 64 bits on 64-bit CPUs and 32 bits on 32-bit CPUs. If you wish to
use a fixed size unsigned integer, you can use `UInt8`, `UInt16`, `UInt32`, or
`UInt64`, which are aliases to the [`SIMD`](/mojo/stdlib/builtin/simd/SIMD)
type.

Signed and unsigned integers of the same bit width can represent the same number
of values, but have different ranges. For example, an `Int8` can represent 256
values ranging from -128 to 127. A `UInt8` can also represent 256 values, but
represents a range of 0 to 255.

Signed and unsigned integers also have different overflow behavior. When a
signed integer overflows outside the range of values that its type can
represent, the value overflows to negative numbers. For example, adding `1` to
`var si: Int8 = 127` results in `-128`.

When an unsigned integer overflows outside the range of values that its type can
represent, the value overflows to zero. So, adding `1` to `var ui: UInt8 = 255`
is equal to `0`.

### Floating-point numbers

Floating-point types represent real numbers. Because not all real numbers can be
expressed in a finite number of bits, floating-point numbers can't represent
every value exactly.

The floating-point types listed in Table 1—`Float64`, `Float32`, and
`Float16`—follow the IEEE 754-2008 standard for representing floating-point
values. Each type includes a sign bit, one set of bits representing an exponent,
and another set representing the fraction or mantissa. Table 2 shows how each of
these types are represented in memory.

<figure>

| Type name | Sign  | Exponent | Mantissa |
| --------- | ----- | -------- | -------- |
| `Float64` | 1 bit | 11 bits  | 52 bits  |
| `Float32` | 1 bit | 8 bits   | 23 bits  |
| `Float16` | 1 bit | 5 bits   | 10 bits  |

<figcaption><b>Table 2.</b> Details of floating-point types</figcaption>
</figure>

Numbers with exponent values of all ones or all zeros represent special values,
allowing floating-point numbers to represent infinity, negative infinity,
signed zeros, and not-a-number (NaN). For more details on how numbers are
represented, see [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) on
Wikipedia.

A few things to note with floating-point values:

* Rounding errors. Rounding may produce unexpected results. For example, 1/3
  can't be represented exactly in these floating-point formats. The more
  operations you perform with floating-point numbers, the more the rounding
  errors accumulate.

* Space between consecutive numbers. The space between consecutive numbers is
  variable across the range of a floating-point number format. For numbers close
  to zero, the distance between consecutive numbers is very small. For large
  positive and negative numbers, the space between consecutive numbers is
  greater than 1, so it may not be possible to represent consecutive integers.

Because the values are approximate, it is rarely useful to compare them with
the equality operator (`==`). Consider the following example:

```mojo
var big_num = 1.0e16
var bigger_num = big_num+1.0
print(big_num == bigger_num)
```

```output
True
```

Comparison operators (`<` `>=` and so on) work with floating point numbers. You
can also use the [`math.isclose()`](/mojo/stdlib/math/math/isclose) function to
compare whether two floating-point numbers are equal within a specified
tolerance.

### Numeric literals

In addition to these numeric types, the standard libraries provides integer and
floating-point literal types,
[`IntLiteral`](/mojo/stdlib/builtin/int_literal/IntLiteral) and
[`FloatLiteral`](/mojo/stdlib/builtin/float_literal/FloatLiteral).

These literal types are used at compile time to represent literal numbers that
appear in the code. In general, you should never instantiate these types
yourself.

Table 3 summarizes the literal formats you can use to represent numbers.

<figure>

| Format                 | Examples        | Notes                                                                                            |
| ---------------------- | --------------- | ------------------------------------------------------------------------------------------------ |
| Integer literal        | `1760`          | Integer literal, in decimal format.                                                              |
| Hexadecimal literal    | `0xaa`, `0xFF`  | Integer literal, in hexadecimal format.<br />Hex digits are case-insensitive.                    |
| Octal literal          | `0o77`          | Integer literal, in octal format.                                                                |
| Binary literal         | `0b0111`        | Integer literal, in binary format.                                                               |
| Floating-point literal | `3.14`, `1.2e9` | Floating-point literal.<br />Must include the decimal point to be interpreted as floating-point. |

<figcaption><b>Table 3.</b> Numeric literal formats</figcaption>
</figure>

At compile time, the literal types are arbitrary-precision (also called
infinite-precision) values, so the compiler can perform compile-time
calculations without overflow or rounding errors.

At runtime the values are converted to finite-precision types—`Int` for
integer values, and `Float64` for floating-point values. (This process of
converting a value that can only exist at compile time into a runtime value is
called *materialization*.)

The following code sample shows the difference between an arbitrary-precision
calculation and the same calculation done using `Float64` values at runtime,
which suffers from rounding errors.

```mojo
var arbitrary_precision = 3.0 * (4.0 / 3.0 - 1.0)
# use a variable to force the following calculation to occur at runtime
var three = 3.0
var finite_precision = three * (4.0 / three - 1.0)
print(arbitrary_precision, finite_precision)
```

```output
1.0 0.99999999999999978
```

### `SIMD` and `DType`

To support high-performance numeric processing, Mojo uses the
[`SIMD`](/mojo/stdlib/builtin/simd/SIMD) type as the basis for its numeric
types. SIMD (single instruction, multiple data) is a processor technology that
allows you to perform an operation on an entire set of operands at once. Mojo's
`SIMD` type abstracts SIMD operations. A `SIMD` value represents a SIMD
*vector*—that is, a fixed-size array of values that can fit into a processor's
register. SIMD vectors are defined by two
[*parameters*](/mojo/manual/parameters/):

* A `DType` value, defining the data type in the vector (for example,
  32-bit floating-point numbers).
* The number of elements in the vector, which must be a power of two.

For example, you can define a vector of four `Float32` values like this:

```mojo
var vec = SIMD[DType.float32, 4](3.0, 2.0, 2.0, 1.0)
```

Math operations on SIMD values are
applied *elementwise*, on each individual element in the vector. For example:

```mojo
var vec1 = SIMD[DType.int8, 4](2, 3, 5, 7)
var vec2 = SIMD[DType.int8, 4](1, 2, 3, 4)
var product = vec1 * vec2
print(product)
```

```output
[2, 6, 15, 28]
```

### Scalar values

The `SIMD` module defines several
[`comptime` values](/mojo/manual/parameters/#comptime-named-parameter-expressions)
that function as *type aliases*—shorthand names for different types of `SIMD`
vectors. In particular, the `Scalar` type is just a `SIMD` vector with a single
element. The numeric types listed in [Table 1](#table-1), like `Int8` and
`Float32` are actually type aliases for different types of scalar values:

```mojo
comptime Scalar = SIMD[size=1]
comptime Int8 = Scalar[DType.int8]
comptime Float32 = Scalar[DType.float32]
```

This may seem a little confusing at first, but it means that whether you're
working with a single `Float32` value or a vector of float32 values,
the math operations go through exactly the same code path.

#### The `DType` type

The `DType` struct describes the different data types that a `SIMD` vector can
hold, and defines a number of utility functions for operating on those data
types. The `DType` struct defines a set of
[`comptime` members](/mojo/manual/parameters/#comptime-members) that act as
identifiers for the different data types, like `DType.int8` and `DType.float32`.
You use these `comptime` members when declaring a `SIMD` vector:

```mojo
var v: SIMD[DType.float64, 16]
```

Note that `DType.float64` isn't a *type*, it's a value that describes a data
type. You can't create a variable with the type `DType.float64`. You can create
a variable with the type `SIMD[DType.float64, 1]` (or  `Float64`, which is the
same thing).

```mojo
from utils.numerics import max_finite, min_finite

def describeDType[dtype: DType]():
    print(dtype, "is floating point:", dtype.is_floating_point())
    print(dtype, "is integral:", dtype.is_integral())
    print("Min/max finite values for", dtype)
    print(min_finite[dtype](), max_finite[dtype]())

describeDType[DType.float32]()
```

```output
float32 is floating point: True
float32 is integral: False
Min/max finite values for float32
-3.4028234663852886e+38 3.4028234663852886e+38
```

There are several other data types in the standard library that also use
the `DType` abstraction.

### Numeric type conversion

[Constructors and implicit conversion](/mojo/manual/lifecycle/life/#constructors-and-implicit-conversion)
documents the circumstances in which Mojo automatically converts a value from
one type to another. Importantly, numeric [operators](/mojo/manual/operators)
**don't** automatically narrow or widen operands to a common type.

You can explicitly convert a `SIMD` value to a different `SIMD` type either
by invoking its [`cast()`](/mojo/stdlib/builtin/simd/SIMD#cast) method or by
passing it as an argument to the constructor of the target type. For example:

```mojo
simd1 = SIMD[DType.float32, 4](2.2, 3.3, 4.4, 5.5)
simd2 = SIMD[DType.int16, 4](-1, 2, -3, 4)
simd3 = simd1 * simd2.cast[DType.float32]()  # Convert with cast() method
print("simd3:", simd3)
simd4 = simd2 + SIMD[DType.int16, 4](simd1)  # Convert with SIMD constructor
print("simd4:", simd4)
```

```output
simd3: [-2.2, 6.6, -13.200001, 22.0]
simd4: [1, 5, 1, 9]
```

You can convert a `Scalar` value by passing it as an argument to the constructor
of the target type. For example:

```mojo
var my_int: Int16 = 12                 # SIMD[DType.int16, 1]
var my_float: Float32 = 0.75           # SIMD[DType.float32, 1]
result = Float32(my_int) * my_float    # Result is SIMD[DType.float32, 1]
print("Result:", result)
```

```output
Result: 9.0
```

You can convert a scalar value of any numeric type to `Int` by passing the value
to the [`Int()`](/mojo/stdlib/builtin/int/Int#__init__) constructor method.
Additionally, you can pass an instance of any struct that implements the
[`Intable`](/mojo/stdlib/builtin/int/Intable) trait or
[`IntableRaising`](/mojo/stdlib/builtin/int/IntableRaising) trait to the `Int()`
constructor to convert that instance to an `Int`.

You can convert an `Int` or `IntLiteral` value to the `UInt` type by passing the
value to the [`UInt()`](/mojo/stdlib/builtin/uint/UInt#__init__) constructor.
You can't convert other numeric types to `UInt` directly, though you can first
convert them to `Int` and then to `UInt`.

## Strings

Mojo's `String` type represents a mutable string. (For Python programmers, note
that this is different from Python's standard string, which is immutable.)
Strings support a variety of operators and common methods.

```mojo
var s: String = "Testing"
s += " Mojo strings"
print(s)
```

```output
Testing Mojo strings
```

Most standard library types conform to the
[`Stringable`](/mojo/stdlib/builtin/str/Stringable) trait, which represents
a type that can be converted to a string. Use `String(value)` to
explicitly convert a value to a string:

```mojo
var s = "Items in list: " + String(5)
print(s)
```

```output
Items in list: 5
```

Or use `String.write` to take variadic `Stringable` types, so you don't have to
call `String()` on each value:

```mojo
var s = String("Items in list: ", 5)
print(s)
```

```output
Items in list: 5
```

### String literals

As with numeric types, the standard library includes a string literal type used
to represent literal strings in the program source. String literals are
enclosed in either single or double quotes.

Adjacent literals are concatenated together, so you can define a long string
using a series of literals broken up over several lines:

```
comptime s = "A very long string which is "
        "broken into two literals for legibility."
```

To define a multi-line string, enclose the literal in three single or double
quotes:

```
comptime s = """
Multi-line string literals let you
enter long blocks of text, including
newlines."""
```

Note that the triple double quote form is also used for API documentation
strings.

A `StringLiteral` will materialize to a `String` when used at run-time:

```mojo
comptime param = "foo"        # type = StringLiteral
var runtime_value = "bar"  # type = String
var runtime_value2 = param # type = String
```

## Booleans

Mojo's `Bool` type represents a boolean value. It can take one of two values,
`True` or `False`. You can negate a boolean value using the `not` operator.

```mojo
var conditionA = False
var conditionB: Bool
conditionB = not conditionA
print(conditionA, conditionB)
```

```output
False True
```

Many types have a boolean representation. Any type that implements the
[`Boolable`](/mojo/stdlib/builtin/bool/Boolable) trait has a boolean
representation. As a general principle, collections evaluate as True if they
contain any elements, False if they are empty; strings evaluate as True if they
have a non-zero length.

## Tuples

Mojo's `Tuple` type represents an immutable tuple consisting of zero or more
values, separated by commas. Tuples can consist of multiple types and you can
index into tuples in multiple ways.

```mojo
# Tuples are immutable and can hold multiple types
example_tuple = Tuple[Int, String](1, "Example")

# Assign multiple variables at once
x, y = example_tuple
print(x, y)

# Get individual values with an index
s = example_tuple[1]
print(s)
```

```output
1 Example
Example
```

You can also create a tuple without explicit typing.

```mojo
example_tuple = (1, "Example")
s = example_tuple[1]
print(s)
```

```output
Example
```

When defining a function, you can explicitly declare the type of tuple elements
in one of two ways:

```mojo
def return_tuple_1() -> Tuple[Int, Int]:
    return Tuple[Int, Int](1, 1)

def return_tuple_2() -> (Int, Int):
    return (2, 2)
```

## Collection types

The Mojo standard library also includes a set of basic collection types that
can be used to build more complex data structures:

* [`List`](/mojo/stdlib/collections/list/List), a dynamically-sized array of
  items.
* [`Dict`](/mojo/stdlib/collections/dict/Dict), an associative array of
  key-value pairs.
* [`Set`](/mojo/stdlib/collections/set/Set), an unordered collection of unique
  items.
* [`Optional`](/mojo/stdlib/collections/optional/Optional)
  represents a value that may or may not be present.

The collection types are *generic types*: while a given collection can only
hold a specific type of value (such as `Int` or `Float64`), you specify the
type at compile time using a [parameter](/mojo/manual/parameters/). For
example, you can create a `List` of `Int` values like this:

```mojo
var l: List[Int] = [1, 2, 3, 4]
# l.append(3.14) # error: FloatLiteral cannot be converted to Int
```

You don't always need to specify the type explicitly. If Mojo can *infer* the
type, you can omit it. For example, when you construct a list from a set of
integer literals, Mojo creates a `List[Int]`.

```mojo
# Inferred type == List[Int]
var l1 = [1, 2, 3, 4]
```

Where you need a more flexible collection, the
[`Variant`](/mojo/stdlib/utils/variant/Variant) type can hold different types
of values. For example, a `Variant[Int32, Float64]` can hold either an `Int32`
*or* a `Float64` value at any given time. (Using `Variant` is not covered in
this section, see the [API docs](/mojo/stdlib/utils/variant/Variant) for more
information.)

The following sections give brief introduction to the main collection types.

### List

[`List`](/mojo/stdlib/collections/list/List) is a dynamically-sized array of
elements. List elements need to conform to the
[`Copyable`](/mojo/stdlib/builtin/value/Copyable) trait. Most of the common
standard library primitives, like `Int`, `String`, and `SIMD` conform to this
trait. You can create a `List` by passing the element type as a parameter,  like
this:

```mojo
var l = List[String]()
```

The `List` type supports a subset of the Python `list` API, including the
ability to append to the list, pop items out of the list, and access list items
using subscript notation.

```mojo
var list = [2, 3, 5]
list.append(7)
list.append(11)
print("Popping last item from list: ", list.pop())
for idx in range(len(list)):
      print(list[idx], end=", ")

```

```output
Popping last item from list:  11
2, 3, 5, 7,
```

Note that the previous code sample leaves out the type parameter when creating
the list. Because the list is being created with a set of `Int` values, Mojo can
*infer* the type from the arguments.

* Mojo supports list, set, and dictionary literals for collection initialization:

  ```mojo
  # List literal, element type infers to Int.
  var nums = [2, 3, 5]
  ```

  You can also use an explicit type if you want a specific element type:

  ```mojo
  var list : List[UInt8] = [2, 3, 5]
  ```

  You can also use list "comprehensions" for compact conditional initialization:

  ```mojo
  var list2 = [x*Int(y) for x in nums for y in list if x != 3]
  ```

* You can't `print()` a list, or convert it directly into a string.

  ```mojo
  # Does not work
  print(list)
  ```

  As shown above, you can print the individual elements in a list as long as
  they're a [`Stringable`](/mojo/stdlib/builtin/str/Stringable) type.

* Iterating a `List` returns an immutable
  [reference](/mojo/manual/values/lifetimes#working-with-references) to each
  item:

```mojo
var list = [2, 3, 4]
for item in list:
      print(item, end=", ")
```

```output
2, 3, 4,
```

If you would like to mutate the elements of the list, capture the reference to
the element with `ref` instead of making a copy:

```mojo
var list = [2, 3, 4]
for ref item in list:     # Capture a ref to the list element
      print(item, end=", ")
      item = 0  # Mutates the element inside the list
print("\nAfter loop:", list[0], list[1], list[2])
```

```output
2, 3, 4,
After loop: 0 0 0
```

You can see that the original loop entries were modified.

### Dict

The [`Dict`](/mojo/stdlib/collections/dict/Dict) type is an associative array
that holds key-value pairs. You can create a `Dict` by specifying the key type
and value type as parameters and using dictionary literals:

```mojo
# Empty dictionary
var empty_dict: Dict[String, Float64] = {}

# Dictionary with initial key-value pairs
var values: Dict[String, Float64] = {"pi": 3.14159, "e": 2.71828}
```

You can also use the constructor syntax:

```mojo
var values = Dict[String, Float64]()
```

The dictionary's key type must conform to the
[`KeyElement`](/mojo/stdlib/collections/dict/#keyelement) trait, and value
elements must conform to the [`Copyable`](/mojo/stdlib/builtin/value/Copyable) trait.

You can insert and remove key-value pairs, update the value assigned to a key,
and iterate through keys, values, or items in the dictionary.

The `Dict` iterators all yield
[references](/mojo/manual/values/lifetimes#working-with-references), which are
copied into the declared name by default, but you can use the `ref` marker to
avoid the copy:

```mojo
var d: Dict[String, Float64] = {
    "plasticity": 3.1,
    "elasticity": 1.3,
    "electricity": 9.7
}
for item in d.items():
    print(item.key, item.value)
```

```output
plasticity 3.1000000000000001
elasticity 1.3
electricity 9.6999999999999993
```

This is an unmeasurable micro-optimization in this case, but is useful when
working with types that aren't `Copyable`.

### Set

The [`Set`](/mojo/stdlib/collections/set/Set) type represents a set of unique
values. You can add and remove elements from the set, test whether a value
exists in the set, and perform set algebra operations, like unions and
intersections between two sets.

Sets are generic and the element type must conform to the
[`KeyElement`](/mojo/stdlib/collections/dict/#keyelement) trait. Like lists and
dictionaries, sets support standard literal syntax, as well as generator
comprehensions:

```mojo
i_like = {"sushi", "ice cream", "tacos", "pho"}
you_like = {"burgers", "tacos", "salad", "ice cream"}
we_like = i_like.intersection(you_like)

print("We both like:")
for item in we_like:
    print("-", item)
```

```output
We both like:
- ice cream
- tacos
```

### Optional

An [`Optional`](/mojo/stdlib/collections/optional/Optional)  represents a
value that may or may not be present. Like the other collection types, it is
generic, and can hold any type that conforms to the
[`Copyable`](/mojo/stdlib/builtin/value/Copyable) trait.

```mojo
# Two ways to initialize an Optional with a value
var opt1 = Optional(5)
var opt2: Optional[Int] = 5
# Two ways to initialize an Optional with no value
var opt3 = Optional[Int]()
var opt4: Optional[Int] = None
```

An `Optional` evaluates as `True` when it holds a value, `False` otherwise. If
the `Optional` holds a value, you can retrieve a reference to the value using
the `value()` method. But calling `value()` on an `Optional` with no value
results in undefined behavior, so you should always guard a call to `value()`
inside a conditional that checks whether a value exists.

```mojo
var opt: Optional[String] = "Testing"
if opt:
    var value_ref = opt.value()
    print(value_ref)
```

```output
Testing
```

Alternately, you can use the `or_else()` method, which returns the stored
value if there is one, or a user-specified default value otherwise:

```mojo
var custom_greeting: Optional[String] = None
print(custom_greeting.or_else("Hello"))

custom_greeting = "Hi"
print(custom_greeting.or_else("Hello"))

```

```output
Hello
Hi
```

## Register-passable, memory-only, and trivial types

In various places in the documentation you'll see references to
register-passable, memory-only, and trivial types. Register-passable and
memory-only types are distinguished based on how they hold data:

* Register-passable types are composed exclusively of fixed-size data types,
  which can (theoretically) be stored in a machine register. A register-passable
  type can include other types, as long as they are also register-passable.
  `Int`, `Bool`, and `SIMD`, for example, are all register-passable types. So
  a register-passable `struct` could include `Int` and `Bool` fields, but not a
  `String` field. Register-passable types are declared with the
  [`@register_passable`](/mojo/manual/decorators/register-passable) decorator.

* Memory-only types consist of all other types that *aren't* specifically
  designated as register-passable types. These types often have pointers or
  references to dynamically-allocated memory. `String`, `List`, and `Dict` are
  all examples of memory-only types.

Register-passable types have a slightly different lifecycle than memory-only
types, which is discussed in [Life of a value](/mojo/manual/lifecycle/life/).

There are also a number of low-level differences in how the Mojo compiler treats
register-passable types versus memory-only types, which you probably won't have
to think about for most Mojo programming. For more information, see
the [`@register_passable`](/mojo/manual/decorators/register-passable) decorator
reference.

Our long-term goal is to make this distinction transparent to the user, and
ensure all APIs work with both register-passable and memory-only types.
But right now you will see a few standard library types that only work with
register-passable types or only work with memory-only types.

In addition to these two categories, Mojo also has "trivial" types. Conceptually
a trivial type is simply a type that doesn't require any custom logic in its
lifecycle methods. The bits that make up an instance of a trivial type can be
copied or moved without any knowledge of what they do. Currently, trivial types
are declared using the
[`@register_passable(trivial)`](/mojo/manual/decorators/register-passable#register_passabletrivial)
decorator. Trivial types shouldn't be limited to only register-passable types,
so in the future we intend to separate trivial types from the
`@register_passable` decorator.

## `AnyType` and `AnyTrivialRegType`

Two other things you'll see in Mojo APIs are references to `AnyType` and
`AnyTrivialRegType`. These are effectively *metatypes*, that is, types of types.

* `AnyType` is a trait that represents a type with a destructor. You'll find
  more discussion of it on the
  [Traits page](/mojo/manual/traits#the-anytype-trait).
* `AnyTrivialRegType` is a metatype representing any Mojo type that's marked
  as a trivial type.

You'll see them in signatures like this:

```mojo
fn any_type_function[ValueType: AnyTrivialRegType](value: ValueType):
    ...
```

You can read this as `any_type_function` has an argument, `value` of type
`ValueType`, where `ValueType` is a register-passable type, determined at
compile time.

There is still some code like this in the standard library, but it's gradually
being migrated to more generic code that doesn't distinguish between
register-passable and memory-only types.
